"""A tool to allow people to import data from Google Trixes

Based on code by Mike Maccana. Cleaned up by Steven Holmes

Requires:
    * google-api-python-client - see http://code.google.com/p/google-api-python-client/wiki/OAuth2
"""

from google.appengine.api import urlfetch, memcache

from xml.etree import ElementTree
from xml.dom import minidom

from django.utils import translation
from django.utils.functional import lazy

from .models import Translator

import logging

def get_oauth2_headers(access_token):
    """Return the HTTP headers required to access an oauth2-protected API"""
    # See http://code.google.com/apis/accounts/docs/OAuth2.html#CallingAnAPI
    # previously 'Authorization': 'OAuth ya29.AHES6ZQNG0OPQdKMIOrPFsiqZ8M42Spl6dx0wqFCNJ6qFA'}
    return {'Authorization':'OAuth ' + access_token}

def pretty_print(element):
    """ElementTree doesn't have its own pretty_print"""
    txt = ElementTree.tostring(element)
    return minidom.parseString(txt).toprettyxml()

def get_gdata_headers(access_token):
    """Return all HTTP headers neccessary for a gdata 3 request"""
    headers = get_oauth2_headers(access_token)
    headers['GData-Version'] = '3.0'
    return headers

def get_spreadsheet_list(access_token):
    """Given an user's oauth access token, return a list of spreadsheets as an XML feed"""
    headers = get_gdata_headers(access_token)
    spreadsheet_list_url = 'https://spreadsheets.google.com/feeds/spreadsheets/private/full'
    response = urlfetch.fetch(spreadsheet_list_url, headers=headers)
    return response.content

def get_entries_from_xml(some_xml):
    """Google docs spreadsheet XML often has lots of entry elements.
    Split some_xml into a list of 'entry' branches"""
    entries = some_xml.findall('.//{http://www.w3.org/2005/Atom}entry')
    if not entries:
        raise ValueError('Could not find any entry elements in supplied XML')
    return entries

def get_title_from_entry(entry_xml):
    """Given an 'entry' branch, get the 'title' element's text"""
    title_nodes = entry_xml.findall('.//{http://www.w3.org/2005/Atom}title')
    if not title_nodes:
        raise ValueError('Could not find any title elements in this entry')
    title = title_nodes[0].text
    return title

def get_entry_with_title(document_feed, document_title):
    """Each 'entry' typically has a 'title'. Return the 'entry' branch that has our document_title."""
    entry_node_for_document = None
    document_feed_xml = ElementTree.fromstring(document_feed)
    entries = get_entries_from_xml(document_feed_xml)
    for entry_node in entries:
        title = get_title_from_entry(entry_node)
        if title == document_title:
            entry_node_for_document = entry_node
    return entry_node_for_document

def get_key_from_entry(entry_xml):
    """Given an 'entry' branch, get the 'link' element's key portion"""
    url_nodes = entry_xml.findall('.//{http://www.w3.org/2005/Atom}link')
    if not url_nodes:
        raise ValueError('Could not find any link elements in this entry')
    key = url_nodes[1].get("href").split("key=")[1]
    return key

def get_entry_with_key(document_feed, document_key):
    """Each 'entry' typically has a 'link' ending in a key/id. Return the 'entry' branch that has our key/id."""
    entry_node_for_document = None
    document_feed_xml = ElementTree.fromstring(document_feed)
    entries = get_entries_from_xml(document_feed_xml)
    for entry_node in entries:
        key = get_key_from_entry(entry_node)
        if key == document_key:
            entry_node_for_document = entry_node
    return entry_node_for_document


def get_content_url_from_entry(entry_node):
    """Given the XML 'entry' for an item, return the 'src' for a 'content' element"""
    content_nodes = entry_node.findall('.//{http://www.w3.org/2005/Atom}content')
    if not content_nodes:
        raise ValueError('Missing content nodes from the document item')
    else:
        worksheet_feed_url = content_nodes[0].attrib.get('src')
    return worksheet_feed_url

def get_list_feed_url_from_worksheets_feed(access_token, worksheets_feed_url, worksheet_name):
    """Given a worksheets_feed, find the URL for worksheet_name """
    headers = get_gdata_headers(access_token)
    response = urlfetch.fetch(worksheets_feed_url, headers=headers)
    worksheets_feed = response.content
    entry_for_worksheet = get_entry_with_title(worksheets_feed, worksheet_name)
    list_feed_url = get_content_url_from_entry(entry_for_worksheet)
    return list_feed_url

def get_cell_content_from_list_feed_url(access_token, list_feed_url):
    """Given a sheet's 'list feed' URL, get the cell data."""
    headers = get_gdata_headers(access_token)
    response = urlfetch.fetch(list_feed_url, headers=headers)
    cell_content_xml = response.content
    return cell_content_xml

def get_row_data_from_row_entry(row_xml):
    """Given the XML for a row, return a list of (column_title, row_title, cell_data) items.
    """
    row_data = []
    cell_data = get_title_from_entry(row_xml)

    for cell_element in row_xml:
        column_title = cell_element.tag.split('}')[-1]
        # As Google has variable tag names based on headers, we want all tags that aren't in the above
        if column_title not in ['id','updated','edited','category','title','content','link']:
            row_title = cell_element.text
            row_data.append((column_title, row_title, cell_data))

    return row_data

def cell_content_xml_to_list_of_rows(cell_content_xml_text):
    """Given worksheet cell XML, return the cell data as a list of rows containing (column_title, row_title, cell_data)
    """
    cell_content_xml = ElementTree.fromstring(cell_content_xml_text)
    row_entries = get_entries_from_xml(cell_content_xml)
    worksheet_data = []
    for row_entry in row_entries:
        row_data = get_row_data_from_row_entry(row_entry)
        worksheet_data.append(row_data)
    return worksheet_data

def get_translator(lang_code):
    """ Get the current Translator object from memcache or fetch it using the
    language code
    """
    translator = memcache.get('translator_%s' % lang_code)
    if not translator:
        try:
            translator = Translator.objects.get(language=lang_code)
            memcache.set('translator_%s' % lang_code, translator)
        except Translator.DoesNotExist:
           logging.error("Missing Translator object. Make sure you've got the latest "
                            "translations and that '%s' is in your allowed languages." % lang_code)
    return translator

def lazy_translate(key):
    """ Override ugettext_lazy to work with sushi_and_tears_redux

    This allows us to to _("My model label") etc in Python files

    """
    def get_translated_string(key):
        lang_code = translation.get_language()
        translator = get_translator(lang_code)
        translated_string = translator.translate(key)
        return translated_string

    return lazy(get_translated_string, unicode)(key)
